package middleware

import (
	"github.com/dgrijalva/jwt-go"
	"github.com/gin-gonic/gin"
	"sport_booking/config"
	"sport_booking/models"
	"sport_booking/utils/message"
	"strings"
	"time"
)

const TokenExpireDuration = time.Hour * 24 // token过期时间

var (
	MyKey = []byte(config.JwtKey) // token密钥
)

type MyClaims struct {
	UUID string `json:"uuid"`
	jwt.StandardClaims
}

/*
生成token
*/
func GenToken(uuid string) (string, int) {
	claims := MyClaims{
		uuid,
		jwt.StandardClaims{
			ExpiresAt: time.Now().Add(TokenExpireDuration).Unix(),
			Issuer:    config.JwtIssuer,
		},
	}
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	signedToken, err := token.SignedString(MyKey)
	if err != nil {
		return "", message.ErrorGenToken
	}
	return signedToken, message.SUCCESS
}

/*
验证token
*/
func ParseToken(tokenString string) (*MyClaims, int) {
	token, err := jwt.ParseWithClaims(tokenString, &MyClaims{},
		func(token *jwt.Token) (interface{}, error) {
			return MyKey, nil
		})
	if err != nil {
		return nil, message.ErrorParseToken
	}
	if claims, ok := token.Claims.(*MyClaims); ok && token.Valid { // 校验token
		return claims, message.SUCCESS
	}
	return nil, message.ErrorInvalidToken
}

/*
基于JWT的认证中间件
*/
func JwtAuthMiddleware() func(c *gin.Context) {
	return func(c *gin.Context) {
		authHeader := c.Request.Header.Get("Authorization")
		if authHeader == "" {
			message.SendMsg(c, message.ErrorHeaderNil)
			c.Abort()
			return
		}
		parts := strings.SplitN(authHeader, " ", 2)
		if len(parts) != 2 || parts[0] != "Bearer" {
			message.SendMsg(c, message.ErrorHeaderFormat)
			c.Abort()
			return
		}
		myClaims, status := ParseToken(parts[1])
		if status != message.SUCCESS {
			message.SendMsg(c, status)
			c.Abort()
			return
		}
		if time.Now().Unix() > myClaims.ExpiresAt {
			message.SendMsg(c, message.ErrorTokenSession)
			c.Abort()
			return
		}
		c.Set("uuid", myClaims.UUID)
		c.Next()
	}
}

/*
用户角色认证中间件
*/
func AuthUserRoleMiddleware() func(c *gin.Context) {
	return func(c *gin.Context) {
		role, status := models.GetUserRoleByUUID(c.GetString("uuid"))
		if status != message.SUCCESS {
			message.SendMsg(c, status)
			c.Abort()
			return
		}
		if role != "admin" {
			message.SendMsg(c, message.ErrorAuthRole)
			c.Abort()
			return
		}
		c.Next()
	}
}
